﻿using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;

namespace Dycox.Drawing
{
    public class DiagramBezierLine : DiagramLine
    {
        public DiagramBezierLine(PointF start, PointF ctl1, PointF ctl2, PointF end)
            : base(4, 4)
        {
            base.SetPoints(0, new PointF[] { start, ctl1, ctl2, end });
        }

        public PointF StartControlPoint
        {
            get { return base.GetPoint(1); }
            set { base.SetPoint(1, value); }
        }

        public PointF EndControlPoint
        {
            get { return base.GetPoint(2); }
            set { base.SetPoint(2, value); }
        }

        protected override Track CreateTrack(PointF[] points)
        {
            return Track.CreateBezier(points[0], points[1], points[2], points[3]);
        }
    }

    public class DiagramStraightLine : DiagramLine
    {
        private DiagramStraightLine()
            : base(2, 2)
        {

        }

        public DiagramStraightLine(PointF start, PointF end)
            : this()
        {
            base.SetPoints(0, new PointF[] { start, end });
        }

        public static DiagramStraightLine CreateLink(DiagramShape shape1, int hpid1, DiagramShape shape2, int hpid2)
        {
            DiagramStraightLine line = new DiagramStraightLine();
            line.Update(shape1, hpid1, shape2, hpid2);
            return line;
        }

        internal void Update(DiagramShape shape1, int hpid1, DiagramShape shape2, int hpid2)
        {
            PointF start = shape1.GetHotPoint(hpid1).Location;
            PointF end = shape2.GetHotPoint(hpid2).Location;

            base.SetPoints(0, new PointF[] { start, end });
        }
    }

    public class DiagramPolyline : DiagramLine
    {
        public DiagramPolyline(params PointF[] points)
            : base(2)
        {
            base.SetPoints(0, points);
        }

        public void AddPoint(PointF point)
        {
            base.SetPoint(base.PointCount, point);
        }

        public static DiagramPolyline CreateLink(DiagramShape rect1, int hpid1, DiagramShape rect2, int hpid2, Direction dir, float turnning = 1f)
        {
            return new DiagramPolyline(CalculatePoints(rect1, hpid1, rect2, hpid2, dir, turnning));
        }

        internal void Update(DiagramShape rect1, int hpid1, DiagramShape rect2, int hpid2, Direction dir, float turnning = 1f)
        {
            var array = CalculatePoints(rect1, hpid1, rect2, hpid2, dir, turnning);

            base.SetPoints(0, array);
        }

        private static PointF[] CalculatePoints(DiagramShape rect1, int hpid1, DiagramShape rect2, int hpid2, Direction dir, float turnning)
        {
            PointF pt1 = rect1.GetHotPoint(hpid1).Location;
            PointF pt2 = rect2.GetHotPoint(hpid2).Location;
            List<PointF> list = new List<PointF>(4);
            list.Add(pt1);

            float diff;

            switch (dir)
            {
                case Direction.North:
                    diff = pt2.Y - pt1.Y;
                    if (diff >= 0)
                        throw new InvalidOperationException();
                    list.Add(new PointF(pt1.X, pt1.Y + diff * turnning));
                    list.Add(new PointF(pt2.X, pt1.Y + diff * turnning));
                    break;
                case Direction.East:
                    diff = pt2.X - pt1.X;
                    if (diff <= 0)
                        throw new InvalidOperationException();

                    list.Add(new PointF(pt1.X + diff * turnning, pt1.Y));
                    list.Add(new PointF(pt1.X + diff * turnning, pt2.Y));
                    break;
                case Direction.South:
                    diff = pt2.Y - pt1.Y;
                    if (diff <= 0)
                        throw new InvalidOperationException();
                    list.Add(new PointF(pt1.X, pt1.Y + diff * turnning));
                    list.Add(new PointF(pt2.X, pt1.Y + diff * turnning));

                    break;
                case Direction.West:
                    diff = pt2.X - pt1.X;
                    if (diff >= 0)
                        throw new InvalidOperationException();

                    list.Add(new PointF(pt1.X + diff * turnning, pt1.Y));
                    list.Add(new PointF(pt1.X + diff * turnning, pt2.Y));
                    break;
                default:
                    break;
            }

            list.Add(pt2);
            return list.ToArray();
        }
    }

    public enum DiagramLinkLineType
    {
        Straight,
        RightAngle,
        Bezier
    }

}
